home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / X11R4 / cmds / X / os / sprite.X11R3 / pdev.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-06-22  |  41.0 KB  |  1,327 lines

  1. /*-
  2.  * pdev.c --
  3.  *    Functions for handling a connection to a client over a pseudo-device.
  4.  *
  5.  *    For each client, we have two buffers -- a 2K output buffer, from
  6.  *    which the client reads, and a 2K request buffer, to which it writes.
  7.  *    The size for the output buffer is based on examination of the size
  8.  *    of buffers used in the old pseudo-device implementation. None
  9.  *    was larger than 2K, so... The input buffer size is based on the
  10.  *    size of Xlib's output buffer -- 2K. This is obviously inadequate for
  11.  *    large amounts of image data, but for most applications it should
  12.  *    be fine.
  13.  *
  14.  *    Requests are processed from the request buffer in order, obviously,
  15.  *    with a write request remaining current until all its data have been
  16.  *    consumed. If an X request crosses a pdev request boundary, it is
  17.  *    copied and collected in a separate area, which is deallocated on the
  18.  *    next call. X requests wholy inside a pdev request are left in the
  19.  *    buffer. The kernel is not told the pdev request has been processed
  20.  *    until all X requests in the pdev request have been handled.
  21.  *
  22.  *    Each time data are written to the read buffer, the pointers are
  23.  *    updated. The stream is not read until the request buffer has
  24.  *    been exhausted.
  25.  *
  26.  * Copyright (c) 1987 by the Regents of the University of California
  27.  *
  28.  * Permission to use, copy, modify, and distribute this
  29.  * software and its documentation for any purpose and without
  30.  * fee is hereby granted, provided that the above copyright
  31.  * notice appear in all copies.  The University of California
  32.  * makes no representations about the suitability of this
  33.  * software for any purpose.  It is provided "as is" without
  34.  * express or implied warranty.
  35.  *
  36.  *
  37.  */
  38. #ifndef lint
  39. static char rcsid[] =
  40. "$Header: /a/X/src/cmds/Xsprite/os/RCS/pdev.c,v 1.12 89/06/22 09:38:41 ouster Exp $ SPRITE (Berkeley)";
  41. #endif lint
  42.  
  43. #define NEED_REPLIES /* For Debugging Only */
  44.  
  45. /*
  46.  * These first two header files must indeed be first, or else this
  47.  * file won't compile.
  48.  */
  49.  
  50. #define Time SpriteTime
  51. #include    <fs.h>
  52. #undef Time
  53. #include    <stdlib.h>
  54.  
  55. #include    "spriteos.h"
  56.  
  57. #include    "Xproto.h"
  58. #include    "opaque.h"
  59.  
  60. #include    <bit.h>
  61. #include    <dev/pdev.h>
  62. #include    <errno.h>
  63. #include    <status.h>
  64. #include    <stdio.h>
  65. #include    <sys/time.h>
  66.  
  67. /*
  68.  * Template for the pseudo-device through which we communicate. Given to
  69.  * one of the printf functions and expects two arguments: the name of the
  70.  * local host and the display number we're using.
  71.  */
  72. #define    DEVICE_TEMPLATE    "/hosts/%s/X%s"
  73.  
  74. #define REASONABLE_TIME        5
  75. #define OUT_BUF_SIZE        2048
  76. #define IN_BUF_SIZE        2048
  77.  
  78. /*
  79.  * The private data maintained for a pseudo-device client
  80.  */
  81. typedef struct {
  82.     int                  streamID;   /* Server stream over which we get the
  83.                      * buffer pointers */
  84.     ClientPtr          client;        /* Client for which this is */
  85.     int                  state;
  86. #define PDEV_REQ_EMPTY            0x0002    /* Request buffer is empty */
  87. #define PDEV_READ_EMPTY            0x0004     /* Read buffer is empty */
  88. #define PDEV_COLLECTING            0x0008    /* Collecting broken X request */
  89. #define PDEV_COLLECTING_HEADER    0x0010    /* Collecting broken X header */
  90.  
  91.     /*
  92.      * Request (inBuf) and read-ahead (outBuf) buffers
  93.      */
  94.     char            outBuf[OUT_BUF_SIZE];
  95.     char              *outPtr;    /* Next place to store data */
  96.  
  97.     char              inBuf[IN_BUF_SIZE];
  98.     Pdev_Request    *reqPtr;    /* Address of next request to process */
  99.     char              *inPtr;        /* Position in current request */
  100.  
  101.     Pdev_BufPtrs      curPtrs;    /* Current pointers for the two buffers */
  102.  
  103.     /*
  104.      * Overflow. If the outBuf fills up, we copy the output data into
  105.      * 'overflow' and copy as much down as possible when the kernel has
  106.      * emptied outBuf.
  107.      *
  108.      * If an X request comes in that is broken across two PDEV_WRITE requests,
  109.      * we allocate enough room to hold it and point bigReq at it, then copy
  110.      * data from inBuf, as it becomes available, into bigReq until the
  111.      * request is fulfilled.
  112.      */
  113.     Buffer            overflow;   /* Any output that won't fit in outBuf */
  114.     char              *bigReq;    /* Points to space for any broken request
  115.                      * that is being assembled. NULL if none */
  116.     char              *bigReqPtr; /* Current position in bigReq */
  117.     int                  need;        /* Number of bytes still needed */
  118. } PdevPrivRec, *PdevPrivPtr;
  119.  
  120. static void       PdevCloseClient();
  121. static char       *PdevReadClient();
  122. static int        PdevWriteClient();
  123.  
  124. int              Pdev_Conn;
  125.  
  126. /*-
  127.  *-----------------------------------------------------------------------
  128.  * Pdev_Init --
  129.  *    Initialize pseudo-device connections.
  130.  *
  131.  * Results:
  132.  *    None.
  133.  *
  134.  * Side Effects:
  135.  *    The pseudo-device for this display is opened. The process will
  136.  *    exit if the device cannot be opened.
  137.  *
  138.  *-----------------------------------------------------------------------
  139.  */
  140. void
  141. Pdev_Init(hostname)
  142.     char    *hostname;    /* The name of the local host */
  143. {
  144.     char          deviceName[100];  /* Path to pseudo-device */
  145.     int              oldPermMask;        /* Previous permission mask */
  146.     ReturnStatus  status;
  147.  
  148.     /*
  149.      * Create the pseudo-device, making sure it's readable and writable
  150.      * by everyone.
  151.      */
  152.  
  153.     sprintf (deviceName, DEVICE_TEMPLATE, hostname, display);
  154.     oldPermMask = umask(0);
  155.     status = Fs_Open (deviceName,
  156.         FS_NON_BLOCKING | FS_CREATE | FS_READ | FS_PDEV_MASTER,
  157.         0666, &Pdev_Conn);
  158.     if (status != 0) {
  159.     errno = Compat_MapCode(status);
  160.     Error (deviceName);
  161.     FatalError ("Could not open pseudo-device %s",
  162.         deviceName);
  163.     }
  164.  
  165.     (void) umask(oldPermMask);
  166. }
  167.  
  168. /*-
  169.  *-----------------------------------------------------------------------
  170.  * PdevSetPtrs --
  171.  *    Set our idea of the state of the two buffers. Called when a
  172.  *    Pdev_BufPtrs structure is read from the kernel. If the read-ahead
  173.  *    buffer has been emptied by the kernel and there's overflow waiting
  174.  *    to go, copy it down and inform the kernel of it.
  175.  *
  176.  * Results:
  177.  *    None.
  178.  *
  179.  * Side Effects:
  180.  *    curPtrs is altered.
  181.  *
  182.  *-----------------------------------------------------------------------
  183.  */
  184. static void
  185. PdevSetPtrs(pdevPriv, bufPtrs)
  186.     PdevPrivPtr    pdevPriv;
  187.     Pdev_BufPtrs      *bufPtrs;
  188. {
  189.     if (DBG(PDEV)) {
  190.     ErrorF("SetPtrs(%d): req %d:%d read %d:%d\n",
  191.            pdevPriv->client ? pdevPriv->client->index : -1,
  192.            bufPtrs->requestFirstByte,
  193.            bufPtrs->requestLastByte,
  194.            bufPtrs->readFirstByte,
  195.            bufPtrs->readLastByte);
  196.     }
  197.  
  198.     /*
  199.      * First update the extent of the request buffer.
  200.      */
  201.     pdevPriv->curPtrs.requestLastByte = bufPtrs->requestLastByte;
  202.     if ((bufPtrs->requestLastByte != -1)  &&
  203.     (pdevPriv->state & PDEV_REQ_EMPTY)) {
  204.         /*
  205.          * We only pay attention to the requestFirstByte if going from
  206.          * an empty to a non-empty buffer, since we think we know where
  207.          * the first request byte actually is.
  208.          */
  209.         pdevPriv->curPtrs.requestFirstByte = bufPtrs->requestFirstByte;
  210.         pdevPriv->reqPtr =
  211.         (Pdev_Request *)&pdevPriv->inBuf[bufPtrs->requestFirstByte];
  212.         pdevPriv->inPtr = (char *)NULL;
  213.         pdevPriv->state &= ~PDEV_REQ_EMPTY;
  214.     }
  215.  
  216.     /*
  217.      * Then the extent of the read buffer.
  218.      */
  219.     pdevPriv->curPtrs.readFirstByte = bufPtrs->readFirstByte;
  220.     if (bufPtrs->readFirstByte == -1) {
  221.     int   numBytes;
  222.  
  223.     pdevPriv->state |= PDEV_READ_EMPTY;
  224.     pdevPriv->outPtr = pdevPriv->outBuf;
  225.  
  226.     numBytes = Buf_Size(pdevPriv->overflow);
  227.     if (numBytes > OUT_BUF_SIZE) {
  228.         numBytes = OUT_BUF_SIZE;
  229.     }
  230.     if (numBytes != 0) {
  231.         /*
  232.          * Copy as much overflow data into the output buffer as possible.
  233.          * The number of bytes actually copied is left in numBytes.
  234.          * pdevPriv->outPtr is set to point to the next place to store
  235.          * data in the buffer.
  236.          */
  237.         numBytes = Buf_GetBytes(pdevPriv->overflow, numBytes,
  238.                     (Byte *)pdevPriv->outBuf);
  239.         pdevPriv->outPtr = &pdevPriv->outBuf[numBytes];
  240.  
  241.         if (numBytes != 0) {
  242.         /*
  243.          * If bytes actually copied, the buffer is no longer empty.
  244.          * Adjust the pointers and inform the kernel of the existence
  245.          * of the data.
  246.          */
  247.         pdevPriv->state &= ~PDEV_READ_EMPTY;
  248.         pdevPriv->curPtrs.readFirstByte = 0;
  249.         pdevPriv->curPtrs.readLastByte = numBytes - 1;
  250.         (void)Fs_IOControl (pdevPriv->streamID,
  251.                     IOC_PDEV_SET_PTRS,
  252.                     sizeof(pdevPriv->curPtrs),
  253.                     (Address)&pdevPriv->curPtrs,
  254.                     0,
  255.                     (Address)NULL);
  256.         }
  257.     } else {
  258.         /*
  259.          * Need to make this -1 so PdevWriteClient works correctly
  260.          * (it adds the number of bytes written to readLastByte without
  261.          * checking its value)
  262.          */
  263.         pdevPriv->curPtrs.readLastByte = -1;
  264.     }
  265.     }
  266. }
  267.     
  268. /*-
  269.  *-----------------------------------------------------------------------
  270.  * PdevRequestHandled --
  271.  *    Tell the kernel that we have handled the request at
  272.  *    pdevPriv->reqPtr and update our own idea of the request buffer.
  273.  *
  274.  * Results:
  275.  *    None.
  276.  *
  277.  * Side Effects:
  278.  *    curPtrs.requestFirstByte is altered, inPtr is NULLed, the
  279.  *    PDEV_REQ_EMPTY flag will be set if the buffer is now empty.
  280.  *
  281.  *-----------------------------------------------------------------------
  282.  */
  283. static void
  284. PdevRequestHandled(pdevPriv)
  285.     PdevPrivPtr    pdevPriv;
  286. {
  287.     ReturnStatus status;
  288.  
  289.     pdevPriv->inPtr = (char *)NULL;
  290.     pdevPriv->curPtrs.requestFirstByte += pdevPriv->reqPtr->hdr.messageSize;
  291.     pdevPriv->reqPtr =
  292.     (Pdev_Request *)&pdevPriv->inBuf[pdevPriv->curPtrs.requestFirstByte];
  293.  
  294.     if (pdevPriv->curPtrs.requestFirstByte >
  295.     pdevPriv->curPtrs.requestLastByte) {
  296.         pdevPriv->state |= PDEV_REQ_EMPTY;
  297.     }
  298.  
  299.     if (DBG(PDEV)) {
  300.     ErrorF("RequestHandled(%d): req %d:%d read %d:%d\n",
  301.            pdevPriv->client ? pdevPriv->client->index : -1,
  302.            pdevPriv->curPtrs.requestFirstByte,
  303.            pdevPriv->curPtrs.requestLastByte,
  304.            pdevPriv->curPtrs.readFirstByte,
  305.            pdevPriv->curPtrs.readLastByte);
  306.     }
  307.  
  308.     status = Fs_IOControl(pdevPriv->streamID, IOC_PDEV_SET_PTRS,
  309.         sizeof(pdevPriv->curPtrs), (Address) &pdevPriv->curPtrs,
  310.         0, (Address) NULL);
  311.     if (status != 0) {
  312.     errno = Compat_MapCode(status);
  313.     if (DBG(PDEV)) {
  314.         Error("RequestHandled: SET_PTRS");
  315.     }
  316.     }
  317.     if (pdevPriv->state & PDEV_REQ_EMPTY) {
  318.     pdevPriv->curPtrs.requestFirstByte =
  319.         pdevPriv->curPtrs.requestLastByte = -1;
  320.     }
  321. }
  322.  
  323. /*-
  324.  *-----------------------------------------------------------------------
  325.  * PdevWaitForReadable --
  326.  *    Wait for a connection to become readable, but only wait a
  327.  *    reasonable amount of time.
  328.  *
  329.  * Results:
  330.  *    Returns 0 if successful, -1 if an error occurs or no
  331.  *    files were readable.
  332.  *
  333.  * Side Effects:
  334.  *    The curPtrs field of the connection is updated.
  335.  *
  336.  *-----------------------------------------------------------------------
  337.  */
  338. static ReturnStatus
  339. PdevWaitForReadable (pdevPriv, selMask)
  340.     PdevPrivPtr    pdevPriv;   /* Connection to read */
  341.     int                  *selMask;   /* Pre-allocated select mask (zeroed) */
  342. {
  343.     Pdev_BufPtrs      bufPtrs;    /* New buffer pointers for stream */
  344.     struct timeval      timeout;    /* Timeout interval for select */
  345.     int                  numReady;   /* Number of ready streams */
  346.     int                  numBytes;   /* Number of bytes read */
  347.     
  348.     Bit_Set (pdevPriv->streamID, selMask);
  349.     timeout.tv_sec = REASONABLE_TIME;
  350.     timeout.tv_usec = 0;
  351.  
  352.     numReady = select(pdevPriv->streamID+1, selMask, (int *) 0, (int *)0,
  353.         &timeout);
  354.     if (numReady < 1) {
  355.     return -1;
  356.     }
  357.  
  358.     numBytes = read(pdevPriv->streamID, (char *) &bufPtrs, sizeof(bufPtrs));
  359.     if (numBytes == -1) {
  360.     if (DBG(PDEV)) {
  361.         Error ("PdevWaitForReadable");
  362.     }
  363.     return (-1);
  364.     }
  365.     if (bufPtrs.magic != PDEV_BUF_PTR_MAGIC) {
  366.     if (DBG(PDEV)) {
  367.         ErrorF ("Buffer magic numbers don't match\n");
  368.     }
  369.     return (-1);
  370.     }
  371.     PdevSetPtrs(pdevPriv, &bufPtrs);
  372.     return (0);
  373. }
  374.  
  375. /*-
  376.  *-----------------------------------------------------------------------
  377.  * PdevConnFail --
  378.  *    Inform a client that it has been denied access.
  379.  *
  380.  * Results:
  381.  *    None.
  382.  *
  383.  * Side Effects:
  384.  *    None.
  385.  *
  386.  *-----------------------------------------------------------------------
  387.  */
  388. static void
  389. PdevConnFail (pdevPriv, swapped, reason)
  390.     PdevPrivPtr    pdevPriv;       /* Failed connection */
  391.     Bool              swapped;        /* TRUE if client is byte-swapped */
  392.     char              *reason;        /* Reason for failure */
  393. {
  394.     int                  *selMask;       /* Mask for selecting on stream */
  395.     struct timeval      timeout;        /* Timeout for select */
  396.     struct timeval      *pTimeOut;
  397.     int                  numReady;       /* Number of streams from select*/
  398.     int                  numBytes;       /* Number of bytes read/written */
  399.     int                  length;            /* Length of reason */
  400.     xConnSetupPrefix    *c;             /* Pointer to returned structure in
  401.                      * read-ahead buffer */
  402.     Pdev_BufPtrs      bufPtrs;        /* New pointers for buffer */
  403.  
  404.  
  405.     if (reason == (char *)NULL) {
  406.     length = 0;
  407.     } else {
  408.     length = strlen (reason);
  409.     }
  410.  
  411.     c = (xConnSetupPrefix *)pdevPriv->outBuf;
  412.     c->success = xFalse;
  413.     c->lengthReason = length;
  414.     c->length = (length + 3) >> 2;
  415.  
  416.     pdevPriv->curPtrs.readFirstByte = 0;
  417.     pdevPriv->curPtrs.readLastByte =
  418.     sizeof(xConnSetupPrefix) + (c->length << 2);
  419.  
  420.     if (!swapped) {
  421.     c->majorVersion = X_PROTOCOL;
  422.     c->minorVersion = X_PROTOCOL_REVISION;
  423.     } else {
  424.     short      n;
  425.  
  426.     swaps(&c->length, n);
  427.     c->majorVersion = lswaps(X_PROTOCOL);
  428.     c->minorVersion = lswaps(X_PROTOCOL_REVISION);
  429.     }
  430.     
  431.     strcpy((char *)&c[1], reason);
  432.  
  433.     if (Fs_IOControl(pdevPriv->streamID, IOC_PDEV_SET_PTRS,
  434.              sizeof(pdevPriv->curPtrs),
  435.              (Address)&pdevPriv->curPtrs,
  436.              0, (Address)NULL) != 0) {
  437.              return;
  438.     }
  439.     
  440.     Bit_Alloc (pdevPriv->streamID+1, selMask);
  441.  
  442.     timeout.tv_sec = REASONABLE_TIME;
  443.     timeout.tv_usec = 0;
  444.     if (DBG(PDEV)) {
  445.     pTimeOut = (struct timeval *)0;
  446.     } else {
  447.     pTimeOut = &timeout;
  448.     }
  449.     
  450.     /*
  451.      * We give the client a REASONABLE_TIME to read the failure structure
  452.      * and message. If it doesn't read it in that time, it loses. When the
  453.      * read-ahead buffer is empty, the client has read the info.
  454.      */
  455.     do {
  456.     Bit_Set (pdevPriv->streamID, selMask);
  457.     numReady = select(pdevPriv->streamID+1, selMask, (int *)0, (int *)0,
  458.         pTimeOut);
  459.     if (numReady < 1) {
  460.         if (DBG(PDEV)) {
  461.         ErrorF("PdevConnFail: didn't read in reasonable time\n");
  462.         }
  463.         break;
  464.     }
  465.     numBytes = read(pdevPriv->streamID, (char *) &bufPtrs,
  466.         sizeof(bufPtrs));
  467.     if ((numBytes != sizeof(bufPtrs))
  468.         || (bufPtrs.magic != PDEV_BUF_PTR_MAGIC)) {
  469.         break;
  470.     }
  471.     if (bufPtrs.readFirstByte == -1) {
  472.         break;
  473.     } else {
  474.         PdevSetPtrs(pdevPriv, &bufPtrs);
  475.         while (!(pdevPriv->state & PDEV_REQ_EMPTY)) {
  476.         if (pdevPriv->reqPtr->hdr.operation == PDEV_CLOSE) {
  477.             /*
  478.              * If we get a close message before the data are all read,
  479.              * just allow the client to go away gracefully -- reply to
  480.              * the close and get the h*** out of here.
  481.              */
  482.             Pdev_Reply    reply;
  483.  
  484.             reply.magic = PDEV_REPLY_MAGIC;
  485.             reply.status = SUCCESS;
  486.             reply.selectBits = 0;
  487.             reply.replySize = 0;
  488.             reply.replyBuf = (Address)NULL;
  489.             reply.signal = 0;
  490.             reply.code = 0;
  491.             (void)Fs_IOControl(pdevPriv->streamID,
  492.                        IOC_PDEV_REPLY,
  493.                        sizeof(reply), (Address)&reply,
  494.                        0, (Address)NULL);
  495.             PdevRequestHandled(pdevPriv);
  496.             goto done;
  497.         }
  498.         /*
  499.          * Anything else we just drop on the floor
  500.          */
  501.         PdevRequestHandled(pdevPriv);
  502.         }
  503.     }
  504.     } while (!pTimeOut || (pTimeOut->tv_sec || pTimeOut->tv_usec));
  505.  
  506. done:
  507.     Bit_Free (selMask);
  508. }
  509.  
  510. /*-
  511.  *-----------------------------------------------------------------------
  512.  * Pdev_EstablishNewConnections --
  513.  *    Accept connections from new clients. 
  514.  *
  515.  * Results:
  516.  *    None returned. pNewClients and *pNumNew are filled in.
  517.  *
  518.  * Side Effects:
  519.  *    AllClientsMask and AllStreamsMask are altered. Fields in the
  520.  *    private structure for the new clients are filled and several
  521.  *    private structures are created.
  522.  *
  523.  *-----------------------------------------------------------------------
  524.  */
  525. void
  526. Pdev_EstablishNewConnections (pNewClients, pNumNew)
  527.     ClientPtr            *pNewClients;    /* Array to fill in */
  528.     int                  *pNumNew;     /* Number of new connections
  529.                      * established */
  530. {
  531.     Pdev_Notify          note;            /* Notification of new stream */
  532.     PdevPrivPtr    pdevPriv;           /* New private information for us */
  533.     ClntPrivPtr          pPriv;            /* New private information for client */
  534.     ClientPtr          client;            /* New client */
  535.     Pdev_Request    *pdevReq;       /* Pointer to current request */
  536.     Pdev_Reply     openReply;          /* Reply to open request */
  537.     Pdev_SetBufArgs    bufArgs;        /* Structure to set r/w buffers */
  538.     int                  numBytes;       /* Number of bytes read */
  539.     xConnClientPrefix    *xccp;            /* Client's description of itself */
  540.     Boolean              swapped;        /* Set TRUE if client is byte-swapped.
  541.                      * FALSE otherwise. */
  542.     Boolean           writeBehind;    /* For IOC_PDEV_WRITE_BEHIND */
  543.  
  544.     pNewClients += *pNumNew;
  545.     writeBehind = TRUE;            /* Turn on write-behind */
  546.  
  547.     while (1) {
  548.     numBytes = read(Pdev_Conn, (char *) ¬e, sizeof(note));
  549.     if ((numBytes != sizeof(note)) || (note.magic != PDEV_NOTIFY_MAGIC)) {
  550.         return;
  551.     }
  552.  
  553.     Ioc_SetBits(note.newStreamID, IOC_NON_BLOCKING);
  554.     
  555.     pdevPriv = (PdevPrivPtr) malloc(sizeof(PdevPrivRec));
  556.     pdevPriv->streamID =                     note.newStreamID;
  557.     pdevPriv->client =                      NullClient;
  558.     pdevPriv->state =                       PDEV_REQ_EMPTY|PDEV_READ_EMPTY;
  559.     pdevPriv->curPtrs.magic =               PDEV_BUF_PTR_MAGIC;
  560.     pdevPriv->curPtrs.requestFirstByte =    -1;
  561.     pdevPriv->curPtrs.requestLastByte =     -1;
  562.     pdevPriv->curPtrs.readFirstByte =       -1;
  563.     pdevPriv->curPtrs.readLastByte =        -1;
  564.     pdevPriv->inPtr =                       (char *)NULL;
  565.     pdevPriv->outPtr =                      pdevPriv->outBuf;
  566.     pdevPriv->overflow =                    Buf_Init(0);
  567.     pdevPriv->bigReq =                      (char *)NULL;
  568.     pdevPriv->bigReqPtr =                    (char *)NULL;
  569.  
  570.     pPriv = (ClntPrivPtr) malloc(sizeof(ClntPrivRec));
  571.     pPriv->readProc =                       PdevReadClient;
  572.     pPriv->writeProc =                      PdevWriteClient;
  573.     pPriv->closeProc =                      PdevCloseClient;
  574.     pPriv->mask =                            (int *)0;
  575.     pPriv->ready =                            (int *)0;
  576.     pPriv->maskWidth =                      0;
  577.     pPriv->devicePrivate =                     (pointer)pdevPriv;
  578.     
  579.     bufArgs.requestBufAddr = pdevPriv->inBuf;
  580.     bufArgs.requestBufSize = IN_BUF_SIZE;
  581.     bufArgs.readBufAddr = pdevPriv->outBuf;
  582.     bufArgs.readBufSize = OUT_BUF_SIZE;
  583.  
  584.     (void)Fs_IOControl(pdevPriv->streamID, IOC_PDEV_SET_BUF,
  585.                sizeof(bufArgs), (Address)&bufArgs,
  586.                0, (Address)NULL);
  587.     (void)Fs_IOControl(pdevPriv->streamID, IOC_PDEV_WRITE_BEHIND,
  588.                sizeof(Boolean), (Address) &writeBehind,
  589.                0, (Address)NULL);
  590.  
  591.     ExpandMasks (pPriv, pdevPriv->streamID);
  592.  
  593.     /*
  594.      * Wait for and handle the OPEN request. If the request comes from
  595.      * an un-authorized source, we return a status of FS_NO_ACCESS. If
  596.      * there's an error, we close the stream and free everything.
  597.      */
  598.     if ((PdevWaitForReadable(pdevPriv, pPriv->ready) != 0) ||
  599.         (pdevPriv->reqPtr->hdr.operation != PDEV_OPEN)) {
  600.         (void) close(pdevPriv->streamID);
  601.         free((char *)pdevPriv);
  602.         free((char *)pPriv);
  603.         continue;
  604.     }
  605.     pdevReq = pdevPriv->reqPtr;
  606.  
  607.     openReply.magic =       PDEV_REPLY_MAGIC;
  608.     openReply.selectBits =     FS_WRITABLE | FS_READABLE;
  609.     openReply.replySize =    0;
  610.     openReply.replyBuf =    (Address)NULL;
  611.     openReply.signal = 0;
  612.     openReply.code = 0;
  613.  
  614.     if (InvalidHost(FamilySprite, pdevReq->param.open.uid,
  615.             pdevReq->param.open.hostID)) {
  616.         openReply.status = FS_NO_ACCESS;
  617.         (void) Fs_IOControl(pdevPriv->streamID, IOC_PDEV_REPLY,
  618.                 sizeof(openReply), (Address)&openReply,
  619.                 0, (Address)NULL);
  620.         
  621.         (void) close(pdevPriv->streamID);
  622.         free((char *)pdevPriv);
  623.         free((char *)pPriv);
  624.         continue;
  625.     } else {
  626.         openReply.status = SUCCESS;
  627.         (void) Fs_IOControl(pdevPriv->streamID, IOC_PDEV_REPLY,
  628.                 sizeof(openReply), (Address)&openReply,
  629.                 0, (Address)NULL);
  630.         
  631.     }
  632.  
  633.     PdevRequestHandled(pdevPriv);
  634.  
  635.     /*
  636.      * Once the OPEN operation has been received, we must wait for the
  637.      * client to write an xConnClientPrefix on the device. Since the
  638.      * Sprite Xlib doesn't pass any extra authorization string junk,
  639.      * we only need to read the prefix.
  640.      */
  641.  
  642.     if (PdevWaitForReadable(pdevPriv, pPriv->ready) != 0) {
  643.         (void) close(pdevPriv->streamID);
  644.         free((char *)pdevPriv);
  645.         free((char *)pPriv);
  646.         continue;
  647.     }
  648.     pdevReq = pdevPriv->reqPtr;
  649.  
  650.     if (pdevReq->hdr.operation == PDEV_WRITE_ASYNC) {
  651.         pdevReq->hdr.operation = PDEV_WRITE;
  652.     }
  653.     if ((pdevReq->hdr.magic != PDEV_REQUEST_MAGIC) ||
  654.         (pdevReq->hdr.operation != PDEV_WRITE) ||
  655.         (pdevReq->hdr.requestSize < sizeof(xConnClientPrefix))) {
  656.         (void) close(pdevPriv->streamID);
  657.         free((char *)pdevPriv);
  658.         free((char *)pPriv);
  659.         continue;
  660.     }
  661.  
  662.     xccp = (xConnClientPrefix *)&pdevReq[1];
  663.     if (xccp->byteOrder != whichByteIsFirst) {
  664.         SwapConnClientPrefix (xccp);
  665.         swapped = TRUE;
  666.     } else {
  667.         swapped = FALSE;
  668.     }
  669.  
  670.     if ((xccp->majorVersion != X_PROTOCOL) ||
  671.         (xccp->minorVersion != X_PROTOCOL_REVISION)) {
  672.         PdevRequestHandled(pdevPriv);
  673.         PdevConnFail(pdevPriv, swapped, "Protocol version mismatch");
  674.         (void) close(pdevPriv->streamID);
  675.         free((char *)pdevPriv);
  676.         free((char *)pPriv);
  677.         continue;
  678.     }
  679.     if ((xccp->nbytesAuthProto != 0) || (xccp->nbytesAuthString != 0)) {
  680.         PdevRequestHandled(pdevPriv);
  681.         PdevConnFail(pdevPriv, swapped,
  682.                 "Can't handle authorization strings");
  683.         (void) close(pdevPriv->streamID);
  684.         free((char *)pdevPriv);
  685.         free((char *)pPriv);
  686.         continue;
  687.     }
  688.  
  689.     client = (ClientPtr)NextAvailableClient();
  690.     if (client == NullClient) {
  691.         PdevRequestHandled(pdevPriv);
  692.         PdevConnFail(pdevPriv, swapped, "Too many clients");
  693.         (void) close(pdevPriv->streamID);
  694.         free((char *)pdevPriv);
  695.         free((char *)pPriv);
  696.         continue;
  697.     } else {
  698.         pdevPriv->client = client;
  699.         client->osPrivate = (pointer)pPriv;
  700.         client->swapped = swapped;
  701.     }
  702.     
  703.     PdevRequestHandled(pdevPriv);
  704.  
  705.     if (DBG(PDEV) || DBG(CONN)) {
  706.         ErrorF ("New Pdev connection: client %d (newID = %d)\n",
  707.             client->index, pdevPriv->streamID);
  708.     }
  709.         
  710.     if ((pdevPriv->state & PDEV_REQ_EMPTY) == 0) {
  711.         /*
  712.          * If there's still stuff left in the request buffer (beyond
  713.          * the initial open request), mark the stream as having input...
  714.          */
  715.         Bit_Set(pdevPriv->streamID, ClientsWithInputMask);
  716.     }
  717.     
  718.     *pNewClients = client;
  719.     pNewClients++;
  720.     (*pNumNew)++;
  721.  
  722.     /*
  723.      * If we're only listening to one client, add the new client's
  724.      * stream to the saved AllClients and AllStreams masks so it is
  725.      * included when the grab is released. Otherwise, we can just
  726.      * add the stream to the regular AllClients and AllStreams
  727.      * masks.
  728.      */
  729.     if (GrabDone) {
  730.         Bit_Set (pdevPriv->streamID, SavedAllClientsMask);
  731.         Bit_Set (pdevPriv->streamID, SavedAllStreamsMask);
  732.     } else {
  733.         Bit_Set (pdevPriv->streamID, AllClientsMask);
  734.         Bit_Set (pdevPriv->streamID, AllStreamsMask);
  735.     }
  736.     }
  737. }
  738.     
  739. /*-
  740.  *-----------------------------------------------------------------------
  741.  * PdevCloseClient --
  742.  *    Some client is being booted. Free up our part of its connection
  743.  *    resources. XXX: Maybe we should wait for the read-ahead buffer to
  744.  *    drain?
  745.  *
  746.  * Results:
  747.  *    None.
  748.  *
  749.  * Side Effects:
  750.  *    The pseudo-device stream is closed and the private data freed
  751.  *    The stream is removed from these masks:
  752.  *        AllStreamsMask, SavedAllStreamsMask, AllClientsMask,
  753.  *        SavedAllClientsMask, ClientsWithInputMask
  754.  *
  755.  *-----------------------------------------------------------------------
  756.  */
  757. static void
  758. PdevCloseClient (pPriv)
  759.     ClntPrivPtr      pPriv;        /* Private data for client whose connection
  760.                  * should be closed */
  761. {
  762.     register PdevPrivPtr pdevPriv;
  763.     register int          streamID;
  764.  
  765.     pdevPriv = (PdevPrivPtr) pPriv->devicePrivate;
  766.     
  767.     streamID = pdevPriv->streamID;
  768.     close(streamID);
  769.     Bit_Clear(streamID, AllStreamsMask);
  770.     Bit_Clear(streamID, SavedAllStreamsMask);
  771.     Bit_Clear(streamID, AllClientsMask);
  772.     Bit_Clear(streamID, SavedAllClientsMask);
  773.     Bit_Clear(streamID, ClientsWithInputMask);
  774.     Buf_Destroy(pdevPriv->overflow, TRUE);
  775.  
  776.     if (pdevPriv->state & PDEV_COLLECTING) {
  777.     free((char *) pdevPriv->bigReq);
  778.     }
  779.         
  780.     free((char *) pdevPriv);
  781. }
  782.  
  783. #define request_length(req, cli) \
  784.      (((cli)->swapped?lswaps(((xReq *)(req))->length):\
  785.       ((xReq *)(req))->length) << 2)
  786.  
  787.  
  788. /*-
  789.  *-----------------------------------------------------------------------
  790.  * PdevReadClient --
  791.  *    Return one request from the given client. If the client is being
  792.  *    naughty, we call ConnectionClosed to close the thing down.
  793.  *    The client will be closed down as well if the stream which acted
  794.  *    up was the only one open for the client. We still return NULL
  795.  *    with status 0 from there, but the client is gone...
  796.  *
  797.  * Results:
  798.  *    The request buffer.
  799.  *
  800.  * Side Effects:
  801.  *    ClientsWithInputMask may be modified.
  802.  *
  803.  *-----------------------------------------------------------------------
  804.  */
  805. /*ARGSUSED*/
  806. static char *
  807. PdevReadClient (pPriv, pStatus, oldbuf)
  808.     ClntPrivPtr          pPriv;        /* Client with input */
  809.     int                  *pStatus;   /* Result of read:
  810.                      *    >0 -- number of bytes in the request
  811.                      *   0  -- not all the request is there
  812.                      *    <0 -- indicates an error */
  813.     char              *oldbuf;    /* The previous buffer */
  814. {
  815.     PdevPrivPtr      pdevPriv;   /* Private data for the client */
  816.     int                  need;        /* Number of bytes needed for the
  817.                      * current request */
  818.     xReq              *reqPtr;    /* Request to give back */
  819.     Pdev_BufPtrs      bufPtrs;    /* New pointers for buffer */
  820.     int                  numBytes;
  821.     Pdev_ReplyData     reply;
  822.  
  823.     pdevPriv = (PdevPrivPtr) pPriv->devicePrivate;
  824.  
  825.     Bit_Clear (pdevPriv->streamID, ClientsWithInputMask);
  826.     
  827.     if (pdevPriv->state & PDEV_REQ_EMPTY) {
  828.     if (Bit_IsSet(pdevPriv->streamID, pPriv->ready)) {
  829.         /*
  830.          * If the request buffer is empty, we think, then we need to see if
  831.          * the kernel has anything for us. However, we only do the read on
  832.          * the device if we actually got here because selecdt says the
  833.          * stream is ready. This prevents a client from hogging the server
  834.          * in an obnoxious fashion...
  835.          */
  836.         numBytes = read(pdevPriv->streamID, &bufPtrs, sizeof(bufPtrs));
  837.         if (numBytes == -1) {
  838.         if (errno != EWOULDBLOCK) {
  839.             if (DBG(PDEV)) {
  840.             Error("Reading buffer pointers");
  841.             }
  842.             *pStatus = -1;
  843.             return((char *)NULL);
  844.         } else {
  845.             /*
  846.              * Wasn't actually anything to read. Go on to
  847.              * the next client...
  848.              */
  849.             *pStatus = 0;
  850.             SchedYield();
  851.             return ((char *)NULL);
  852.         }
  853.         }
  854.         if ((numBytes != sizeof(bufPtrs)) ||
  855.         (bufPtrs.magic != PDEV_BUF_PTR_MAGIC)) {
  856.             if (DBG(PDEV)) {
  857.             ErrorF("Improper data when reading buffer pointers");
  858.             }
  859.             *pStatus = -1;
  860.             return ((char *)NULL);
  861.         }
  862.         PdevSetPtrs(pdevPriv, &bufPtrs);
  863.     }
  864.     if (pdevPriv->state & PDEV_REQ_EMPTY) {
  865.         /*
  866.          * If there are still no requests, there's nothing more to
  867.          * be done. PdevSetPtrs will have copied any overflow
  868.          * to the read-ahead buffer, so...
  869.          */
  870.         *pStatus = 0;
  871.         SchedYield();
  872.         return ((char *)NULL);
  873.     }
  874.     }
  875.  
  876.     Bit_Clear (pdevPriv->streamID, pPriv->ready);
  877.     
  878.     /*
  879.      * Process the requests until we get one that's a WRITE request,
  880.      * then set inPtr to the data for the request and break out
  881.      * of the loop.
  882.      */
  883.     while ((pdevPriv->inPtr == (char *)NULL) &&
  884.        !(pdevPriv->state & PDEV_REQ_EMPTY))
  885.     {
  886.     switch (pdevPriv->reqPtr->hdr.operation) {
  887.         case PDEV_WRITE_ASYNC:
  888.         case PDEV_WRITE:
  889.         if (DBG(PDEV)) {
  890.             ErrorF("client %d: PDEV_WRITE(%d)\n",
  891.                pdevPriv->client->index,
  892.                pdevPriv->reqPtr->hdr.requestSize);
  893.         }
  894.         pdevPriv->inPtr = (char *)&pdevPriv->reqPtr[1];
  895.         break;
  896.         case PDEV_CLOSE:
  897.         /*
  898.          * We like closes. We just return -1 to cause the
  899.          * connection to be aborted.
  900.          */
  901.         if (DBG(PDEV) || DBG(CONN)) {
  902.             ErrorF("client %d: PDEV_CLOSE\n", pdevPriv->client->index);
  903.         }
  904.         reply.magic = PDEV_REPLY_MAGIC;
  905.         reply.status = SUCCESS;
  906.         reply.selectBits = 0;
  907.         reply.replySize = 0;
  908.         reply.replyBuf = (Address)NULL;
  909.         reply.signal = 0;
  910.         reply.code = 0;
  911.         (void)Fs_IOControl(pdevPriv->streamID,
  912.                    IOC_PDEV_REPLY,
  913.                    sizeof(reply), (Address)&reply,
  914.                    0, (Address)NULL);
  915.         PdevRequestHandled(pdevPriv);
  916.         *pStatus = -1;
  917.         return ((char *)NULL);
  918.         case PDEV_IOCTL: {
  919.         /*
  920.          * All this should be unnecessary, but we reply to it
  921.          * anyway and pretend we know what we're doing when it
  922.          * comes to the IOC_NUM_READABLE
  923.          */
  924.         char    *inBuffer;
  925.         int    replyBuf;
  926.         int    command;
  927.         
  928.         reply.magic = PDEV_REPLY_MAGIC;
  929.         reply.status = SUCCESS;
  930.         reply.selectBits =
  931.             ((pdevPriv->state & PDEV_READ_EMPTY)?0:FS_READABLE) |
  932.             FS_WRITABLE;
  933.         reply.replySize = 0;
  934.         reply.replyBuf = (Address)&replyBuf;
  935.         
  936.         if (pdevPriv->reqPtr->hdr.requestSize) {
  937.             inBuffer = (char *)&pdevPriv->reqPtr[1];
  938.         } else {
  939.             inBuffer = (char *)NULL;
  940.         }
  941.         if (DBG(PDEV)) {
  942.             ErrorF("client %d: PDEV_IOCTL(%x, %d, %x, %d, ...)\n",
  943.                pdevPriv->client->index,
  944.                pdevPriv->reqPtr->param.ioctl.command,
  945.                pdevPriv->reqPtr->hdr.requestSize,
  946.                inBuffer,
  947.                pdevPriv->reqPtr->hdr.replySize);
  948.         }
  949.         
  950.         switch (pdevPriv->reqPtr->param.ioctl.command) {
  951.             case IOC_NUM_READABLE:
  952.             /*
  953.              * XXX: This is already handled by the
  954.              * kernel since it knows how much it has
  955.              * more accurately than I do.
  956.              */
  957.             reply.replySize = sizeof(int);
  958.             replyBuf = pdevPriv->curPtrs.readLastByte -
  959.                 pdevPriv->curPtrs.readFirstByte;
  960.             break;
  961.             case IOC_SET_BITS:
  962.             case IOC_SET_FLAGS:
  963.             break;
  964.             case IOC_CLEAR_BITS:
  965.             case IOC_GET_FLAGS:
  966.             replyBuf = 0;
  967.             reply.replySize = sizeof(int);
  968.             break;
  969.             default:
  970.             if (DBG(PDEV)) {
  971.                 ErrorF("Invalid IOCTL %x\n",
  972.                    pdevPriv->reqPtr->param.ioctl.command);
  973.             }
  974.             reply.status = FS_DEVICE_OP_INVALID;
  975.             break;
  976.         }
  977.         reply.signal = 0;
  978.         reply.code = 0;
  979.         if (reply.replySize > 0) {
  980.             *(int *)reply.data = replyBuf;
  981.             command = IOC_PDEV_SMALL_REPLY;
  982.         } else {
  983.             command = IOC_PDEV_REPLY;
  984.         }
  985.         (void)Fs_IOControl(pdevPriv->streamID,
  986.                    command,
  987.                    sizeof(reply), (Address)&reply,
  988.                    0, (Address)NULL);
  989.         PdevRequestHandled(pdevPriv);
  990.         break;
  991.         }
  992.         default:
  993.         /*
  994.          * Bad pseudo-device request -- close the beastie down
  995.          */
  996.         reply.magic = PDEV_REPLY_MAGIC;
  997.         reply.status = FS_DEVICE_OP_INVALID;
  998.         reply.selectBits = 0;
  999.         reply.replySize = 0;
  1000.         reply.replyBuf = (Address)NULL;
  1001.         reply.signal = 0;
  1002.         reply.code = 0;
  1003.         if (DBG(PDEV)) {
  1004.             ErrorF("Bad new pdev request %d client %d\n",
  1005.                pdevPriv->reqPtr->hdr.operation,
  1006.                pdevPriv->client->index);
  1007.         }
  1008.         (void)Fs_IOControl(pdevPriv->streamID,
  1009.                    IOC_PDEV_REPLY,
  1010.                    sizeof(reply), (Address)&reply,
  1011.                    0, (Address)NULL);
  1012.         PdevRequestHandled(pdevPriv);
  1013.         *pStatus = -1;
  1014.         return ((char *)NULL);
  1015.     }
  1016.     }
  1017.     if (pdevPriv->inPtr == (char *)NULL) {
  1018.     /*
  1019.      * If didn't reach a PDEV_WRITE request, there's nothing more
  1020.      * to do...
  1021.      */
  1022.     Bit_Clear(pdevPriv->streamID, ClientsWithInputMask);
  1023.     SchedYield();
  1024.     *pStatus = 0;
  1025.     return ((char *)NULL);
  1026.     }
  1027.     
  1028.     if (pdevPriv->state & PDEV_COLLECTING) {
  1029.     /*
  1030.      * Collecting an X request that was broken across a WRITE boundary.
  1031.      * bigReqPtr points to the next place to store stuff for the
  1032.      * request, while need contains the number of bytes still needed
  1033.      * to fill the request. bigReq has been allocated to contain
  1034.      * the requisite space.
  1035.      */
  1036.     need = min(pdevPriv->need, pdevPriv->reqPtr->hdr.requestSize);
  1037.     bcopy(pdevPriv->inPtr, pdevPriv->bigReqPtr, need);
  1038.     pdevPriv->bigReqPtr += need;
  1039.     pdevPriv->need -= need;
  1040.     pdevPriv->inPtr += need;
  1041.     if (pdevPriv->need != 0) {
  1042.         PdevRequestHandled(pdevPriv);
  1043.         *pStatus = 0;
  1044.         return ((char *)NULL);
  1045.     } else {
  1046.         pdevPriv->reqPtr->hdr.requestSize -= need;
  1047.         need = request_length(pdevPriv->bigReq, pdevPriv->client);
  1048.         *pStatus = need;
  1049.         pdevPriv->state &= ~PDEV_COLLECTING;
  1050.         Bit_Set(pdevPriv->streamID, ClientsWithInputMask);
  1051.         if (DBG(PDEV)) {
  1052.         ErrorF("XRequest(%d, %d) #%d\n", pdevPriv->client->index,
  1053.                ((xReq *)pdevPriv->bigReq)->reqType,
  1054.                pdevPriv->client->sequence + 1);
  1055.         }
  1056.         return (pdevPriv->bigReq);
  1057.     }
  1058.     } else if (pdevPriv->state & PDEV_COLLECTING_HEADER) {
  1059.     /*
  1060.      * The header for the request was broken across a WRITE boundary.
  1061.      * bigReqPtr points to the place we left off in the header,
  1062.      * while bigReq points to a piece of memory big enough for
  1063.      * an xReq and no more.  Once the entire request header is seen,
  1064.      * we can allocate a large enough buffer for the entire request.
  1065.      */
  1066.     need = min(pdevPriv->need, pdevPriv->reqPtr->hdr.requestSize);
  1067.     bcopy(pdevPriv->inPtr, pdevPriv->bigReqPtr, need);
  1068.     pdevPriv->bigReqPtr += need;
  1069.     pdevPriv->need -= need;
  1070.     pdevPriv->inPtr += need;
  1071.     if (pdevPriv->need != 0) {
  1072.         /*
  1073.          * XXX: Shouldn't happen
  1074.          */
  1075.         PdevRequestHandled(pdevPriv);
  1076.         *pStatus = 0;
  1077.         return ((char *)NULL);
  1078.     } else {
  1079.         /*
  1080.          * We've now gotten a complete header. To keep this simple
  1081.          * we just allocate the needed buffer, copy the header in,
  1082.          * switch to COLLECTING state from COLLECTING_HEADER and
  1083.          * return a blocked read. We'll get called again (very
  1084.          * soon) to fill out the request...
  1085.          */
  1086.         xReq    *xreq;
  1087.  
  1088.         xreq = (xReq *)pdevPriv->bigReq;
  1089.         need = request_length(xreq, pdevPriv->client);
  1090.         pdevPriv->bigReq = malloc((unsigned) need);
  1091.         bcopy(xreq, pdevPriv->bigReq, sizeof(xReq));
  1092.         pdevPriv->bigReqPtr += sizeof(xReq);
  1093.         pdevPriv->need = need - sizeof(xReq);
  1094.         pdevPriv->state ^= PDEV_COLLECTING|PDEV_COLLECTING_HEADER;
  1095.         free((char *) xreq);
  1096.         *pStatus = 0;
  1097.         return ((char *)NULL);
  1098.     }
  1099.     }
  1100.     if (pdevPriv->bigReq != (char *)NULL) {
  1101.     /*
  1102.      * If we're not collecting anything and there's something
  1103.      * pointed to by bigReq, it must be old and should be
  1104.      * deallocated.
  1105.      */
  1106.     free((char *) pdevPriv->bigReq);
  1107.     pdevPriv->bigReq = (char *)NULL;
  1108.     }
  1109.     if (pdevPriv->reqPtr->hdr.requestSize < sizeof(xReq)) {
  1110.     if (pdevPriv->reqPtr->hdr.requestSize != 0) {
  1111.         /*
  1112.          * Only go into the COLLECTING_HEADER state if there are
  1113.          * data bytes left in the request (i.e. it's really a broken
  1114.          * header, not just an exhausted WRITE request).
  1115.          */
  1116.         pdevPriv->state |= PDEV_COLLECTING_HEADER;
  1117.         pdevPriv->bigReq = (char *) malloc(sizeof(xReq));
  1118.         bcopy(pdevPriv->inPtr, pdevPriv->bigReq,
  1119.             pdevPriv->reqPtr->hdr.requestSize);
  1120.         pdevPriv->bigReqPtr =
  1121.         pdevPriv->bigReq + pdevPriv->reqPtr->hdr.requestSize;
  1122.         pdevPriv->need = sizeof(xReq) - pdevPriv->reqPtr->hdr.requestSize;
  1123.     }
  1124.     PdevRequestHandled(pdevPriv);
  1125.     *pStatus = 0;
  1126.     return ((char *)NULL);
  1127.     } else {
  1128.     /*
  1129.      * Can actually figure out the size of the request. Store it
  1130.      * in 'need'
  1131.      */
  1132.     need = request_length (pdevPriv->inPtr, pdevPriv->client);
  1133.     
  1134.     if (need > pdevPriv->reqPtr->hdr.requestSize) {
  1135.         /*
  1136.          * The X request didn't fit in PDEV_WRITE request, so
  1137.          * we mark the stream as collecting a (big) request, copy
  1138.          * in whatever data we have and return a blocked read status.
  1139.          * Note we DO NOT yield the server since there may be another
  1140.          * write request pending.
  1141.          */
  1142.         pdevPriv->state |= PDEV_COLLECTING;
  1143.         pdevPriv->bigReq = (char *) malloc((unsigned) need);
  1144.         bcopy(pdevPriv->inPtr, pdevPriv->bigReq,
  1145.             pdevPriv->reqPtr->hdr.requestSize);
  1146.         pdevPriv->bigReqPtr =
  1147.         pdevPriv->bigReq + pdevPriv->reqPtr->hdr.requestSize;
  1148.         pdevPriv->need = need - pdevPriv->reqPtr->hdr.requestSize;
  1149.         PdevRequestHandled(pdevPriv);
  1150.         *pStatus = 0;
  1151.         return ((char *)NULL);
  1152.     } else {
  1153.         reqPtr = (xReq *)pdevPriv->inPtr;
  1154.         pdevPriv->inPtr += need;
  1155.         pdevPriv->reqPtr->hdr.requestSize -= need;
  1156.         *pStatus = need;
  1157.         Bit_Set(pdevPriv->streamID, ClientsWithInputMask);
  1158.         if (DBG(PDEV)) {
  1159.         ErrorF("XRequest(%d, %d) #%d\n", pdevPriv->client->index,
  1160.                reqPtr->reqType, pdevPriv->client->sequence+1);
  1161.         }
  1162.         return ((char *)reqPtr);
  1163.     }
  1164.     }
  1165. }
  1166.  
  1167. /*-
  1168.  *-----------------------------------------------------------------------
  1169.  * PdevWriteClient --
  1170.  *    Write data to the client. Data are copied into the read buffer
  1171.  *    as much as possible. Data that cannot fit in the read buffer are
  1172.  *    placed in the overflow buffer until the kernel catches up with us,
  1173.  *    at which point the data are copied back down to the read buffer.
  1174.  *    Output packets may be broken at arbitrary points and all
  1175.  *    transmissions are rounded to be a multiple of 32 bits long. Because
  1176.  *    of this, if the entire packet fits into the read buffer, the
  1177.  *    pad bytes do too.
  1178.  *
  1179.  * Results:
  1180.  *    Number of bytes written.
  1181.  *
  1182.  * Side Effects:
  1183.  *    The data bytes are stuffed into the buffer for the client, awaiting
  1184.  *    a read request from the client.
  1185.  *
  1186.  *-----------------------------------------------------------------------
  1187.  */
  1188. static int
  1189. PdevWriteClient (pPriv, numBytes, xRepPtr)
  1190.     ClntPrivPtr      pPriv;        /* Client to receive the data */
  1191.     int              numBytes;     /* Number of bytes (unrounded) */
  1192.     Address          xRepPtr;     /* The data bytes */
  1193. {
  1194.     int                      rndNumBytes;    /* Number of bytes, rounded to a
  1195.                          * longword */
  1196.     int                      pad = 0;        /* Padding bytes */
  1197.     register int          padding;        /* Number of bytes needed */
  1198.     register PdevPrivPtr    pdevPriv;        /* Data private to client */
  1199.     ReturnStatus        status;
  1200.  
  1201.     rndNumBytes = (numBytes + 3) & ~3;
  1202.  
  1203.     pdevPriv = (PdevPrivPtr) pPriv->devicePrivate;
  1204.     
  1205.     
  1206.     padding = rndNumBytes - numBytes;
  1207.  
  1208.     if (pdevPriv->curPtrs.readLastByte == (OUT_BUF_SIZE - 1)) {
  1209.     /*
  1210.      * Output buffer is full -- must copy data to overflow buffer
  1211.      */
  1212.     if (DBG(PDEV)) {
  1213.         ErrorF("WriteClient(%d): overflow -- ", pdevPriv->client->index);
  1214.     }
  1215.     Buf_AddBytes(pdevPriv->overflow, numBytes, (Byte *)xRepPtr);
  1216.     if (padding != 0) {
  1217.         Buf_AddBytes(pdevPriv->overflow, padding, (Byte *)&pad);
  1218.     }
  1219.     } else {
  1220.     int       numWrite;
  1221.  
  1222.     numWrite = min(numBytes,OUT_BUF_SIZE - pdevPriv->curPtrs.readLastByte);
  1223.     bcopy((char *) xRepPtr, (char *) pdevPriv->outPtr, numWrite);
  1224.     numBytes -= numWrite;
  1225.  
  1226.     /*
  1227.      * Update the output pointers. Note that since readLastByte starts
  1228.      * at -1, adding numWrite will point to the last valid byte of data
  1229.      * in the buffer...
  1230.      */
  1231.     pdevPriv->curPtrs.readLastByte += numWrite;
  1232.     pdevPriv->outPtr += numWrite;
  1233.     
  1234.     if (numBytes != 0) {
  1235.         /*
  1236.          * Didn't manage to fit the entire request into the read-ahead
  1237.          * buffer. Copy excess to overflow.
  1238.          */
  1239.         Buf_AddBytes(pdevPriv->overflow,
  1240.              numBytes,
  1241.              ((Byte *)xRepPtr) + numWrite);
  1242.         if (padding != 0) {
  1243.         Buf_AddBytes(pdevPriv->overflow,
  1244.                  padding,
  1245.                  (Byte *)&pad);
  1246.         }
  1247.     } else if (padding != 0) {
  1248.         /*
  1249.          * Because the buffer is a multiple of 32-bits long, any rounding
  1250.          * that needs to be done is guaranteed to fit if the unrounded
  1251.          * packet fit.
  1252.          */
  1253.         bcopy((char *) &pad, pdevPriv->outPtr, padding);
  1254.         pdevPriv->curPtrs.readLastByte += padding;
  1255.         pdevPriv->outPtr += padding;
  1256.     }
  1257.  
  1258.     /*
  1259.      * Inform kernel of new read buffer extents
  1260.      */
  1261.     status = Fs_IOControl(pdevPriv->streamID, IOC_PDEV_SET_PTRS,
  1262.         sizeof(pdevPriv->curPtrs), (Address) &pdevPriv->curPtrs,
  1263.         0, (Address) NULL);
  1264.     if (status != 0) {
  1265.         errno = Compat_MapCode(status);
  1266.         if (DBG(PDEV)) {
  1267.         Error("WriteClient: SET_PTRS");
  1268.         }
  1269.     }
  1270.     if (DBG(PDEV)) {
  1271.         ErrorF("WriteClient(%d): req %d:%d read %d:%d ",
  1272.            pdevPriv->client->index,
  1273.            pdevPriv->curPtrs.requestFirstByte,
  1274.            pdevPriv->curPtrs.requestLastByte,
  1275.            pdevPriv->curPtrs.readFirstByte,
  1276.            pdevPriv->curPtrs.readLastByte);
  1277.         
  1278.         switch (((xReply *)xRepPtr)->generic.type) {
  1279.         case X_Reply:
  1280.             ErrorF("Reply to %d\n",
  1281.                ((xReply *)xRepPtr)->generic.sequenceNumber);
  1282.             break;
  1283.         case X_Error:
  1284.             ErrorF("Error for %d\n",
  1285.                ((xReply *)xRepPtr)->generic.sequenceNumber);
  1286.             break;
  1287.         case KeyPress: ErrorF("KeyPress event\n"); break;
  1288.         case KeyRelease: ErrorF("KeyRelease event\n"); break;
  1289.         case ButtonPress: ErrorF("ButtonPress event\n"); break;
  1290.         case ButtonRelease: ErrorF("ButtonRelease event\n"); break;
  1291.         case MotionNotify: ErrorF("MotionNotify event\n"); break;
  1292.         case EnterNotify: ErrorF("EnterNotify event\n"); break;
  1293.         case LeaveNotify: ErrorF("LeaveNotify event\n"); break;
  1294.         case FocusIn: ErrorF("FocusIn event\n"); break;
  1295.         case FocusOut: ErrorF("FocusOut event\n"); break;
  1296.         case KeymapNotify: ErrorF("KeymapNotify event\n"); break;
  1297.         case Expose: ErrorF("Expose event\n"); break;
  1298.         case GraphicsExpose: ErrorF("GraphicsExpose event\n"); break;
  1299.         case NoExpose: ErrorF("NoExpose event\n"); break;
  1300.         case VisibilityNotify: ErrorF("VisibilityNotify event\n"); break;
  1301.         case CreateNotify: ErrorF("CreateNotify event\n"); break;
  1302.         case DestroyNotify: ErrorF("DestroyNotify event\n"); break;
  1303.         case UnmapNotify: ErrorF("UnmapNotify event\n"); break;
  1304.         case MapNotify: ErrorF("MapNotify event\n"); break;
  1305.         case MapRequest: ErrorF("MapRequest event\n"); break;
  1306.         case ReparentNotify: ErrorF("ReparentNotify event\n"); break;
  1307.         case ConfigureNotify: ErrorF("ConfigureNotify event\n"); break;
  1308.         case ConfigureRequest: ErrorF("ConfigureRequest event\n"); break;
  1309.         case GravityNotify: ErrorF("GravityNotify event\n"); break;
  1310.         case ResizeRequest: ErrorF("ResizeRequest event\n"); break;
  1311.         case CirculateNotify: ErrorF("CirculateNotify event\n"); break;
  1312.         case CirculateRequest: ErrorF("CirculateRequest event\n"); break;
  1313.         case PropertyNotify: ErrorF("PropertyNotify event\n"); break;
  1314.         case SelectionClear: ErrorF("SelectionClear event\n"); break;
  1315.         case SelectionRequest: ErrorF("SelectionRequest event\n"); break;
  1316.         case SelectionNotify: ErrorF("SelectionNotify event\n"); break;
  1317.         case ColormapNotify: ErrorF("ColormapNotify event\n"); break;
  1318.         case ClientMessage: ErrorF("ClientMessage event\n"); break;
  1319.         case MappingNotify: ErrorF("MappingNotify event\n"); break;
  1320.         default:
  1321.             ErrorF("Data\n");
  1322.         }
  1323.     }
  1324.     }
  1325.     return (numBytes);
  1326. }
  1327.